package cn.i7baozh.starter.gateway.handler;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.entity.ContentType;
import org.reactivestreams.Publisher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;

/**
 * 对响应统一包装
 * order 要小于 -1
 * https://blog.csdn.net/zx156955/article/details/121670681
 * 如果返回不是json的话（一般项目都是JSON），就不要转为json，是什么格式就用什么格式解析,不然会报错，格式错误。
 * 十分鸡肋！！！！！！
 * @author : baoqi.zhang
 * @date :   2022/5/17 15:18
 */
@Slf4j
//@Component
public class GlobalResponseWrapperHandler implements GlobalFilter, Ordered {

    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpResponse originalResponse = exchange.getResponse();
        DataBufferFactory dataBufferFactory = originalResponse.bufferFactory();
        ServerHttpResponseDecorator decorator = new ServerHttpResponseDecorator(originalResponse) {

            @Override
            public HttpHeaders getHeaders() {
                HttpHeaders headers = super.getHeaders();
                headers.setContentType(MediaType.APPLICATION_JSON);
                return headers;
            }


            @Override
            public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
                if (body instanceof Flux) {
                    //只有客户端响应为json时 才可以强制对其改变 因此局限性为依赖响应端, 而且返回要用dto进行包装不然无响应
                    if (ContentType.APPLICATION_JSON.toString().equals(originalResponse.getHeaders().getFirst(HttpHeaders.CONTENT_TYPE))
                            || "application/json".equals(originalResponse.getHeaders().getFirst(HttpHeaders.CONTENT_TYPE))) {
                        Flux<? extends DataBuffer> fluxBody = (Flux<? extends DataBuffer>) body;
                        return super.writeWith(fluxBody.map(dataBuffer -> {
                            byte[] content = new byte[dataBuffer.readableByteCount()];
                            dataBuffer.read(content);
                            DataBufferUtils.release(dataBuffer);
                            String responseContent = new String(content, StandardCharsets.UTF_8);

                            byte[] updatedContent = new byte[0];
                            try {
                                updatedContent = objectMapper.writeValueAsBytes(GatewayResult.success(responseContent));
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                            return dataBufferFactory.wrap(updatedContent);
                        }));
                    }
                }
                return super.writeWith(body);
            }
        };
        return chain.filter(exchange.mutate().response(decorator).build());
    }

    @Override
    public int getOrder() {
        return -100;
    }
}
